﻿using KAsFrame.Common.Dto;
using KAsFrame.Common.Extensions;
using SqlSugar;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq.Expressions;

namespace KAsFrame.Common.Application
{
    /// <summary>
    /// 通用应用服务
    /// </summary>
    /// <typeparam name="TPrimaryKeyType">主键类型</typeparam>
    /// <typeparam name="T">实体类</typeparam>
    /// <typeparam name="TCreateDto">实体创建Dto类</typeparam>
    /// <typeparam name="TUpdateDto">实体更新Dto类</typeparam>
    /// <typeparam name="TDto"></typeparam>
    public abstract class CommonCurdAppService<TPrimaryKeyType, T, TCreateDto, TUpdateDto, TDto> :
        ICommonCurdAppService<TPrimaryKeyType, T, TCreateDto, TUpdateDto, TDto>
        where T : IEntity<TPrimaryKeyType>, new()
        where TCreateDto : IEntityDto<TPrimaryKeyType>, new()
        where TUpdateDto : IEntityDto<TPrimaryKeyType>, new()
        where TDto : IEntityDto<TPrimaryKeyType>, new()
    {
        protected ISqlSugarClient _db;

        public CommonCurdAppService(ISqlSugarClient db)
        {
            _db = db;
        }

        public virtual async Task<long> CreateAsync(TCreateDto createDto)
        {
            var entity = createDto.SimpleMapTo<T>();
            entity.Id = default;
            return await _db.Insertable(entity).ExcutedReturnIdAsync<T,TPrimaryKeyType>();
        }

        public virtual async Task<bool> UpdateAsync(TUpdateDto updateDto)
        {
            var entity = await _db.Queryable<T>().Where(x => x.Id.Equals(updateDto.Id)).SingleAsync();
            updateDto.SimpleMapTo(entity);
            return await _db.Updateable(entity).ExecuteCommandHasChangeAsync();
        }

        public virtual async Task<bool> DeleteAsync(TPrimaryKeyType id)
        {
            // 实体继承IDeleteEntity接口，则进行逻辑删除，否则进行物理删除
            if (typeof(T).GetInterfaces().Any(x => x == typeof(IDeleteEntity)))
                return await _db.Deleteable<T>().In(id).IsLogic().ExecuteCommandAsync() > 0;
            else
                return await _db.Deleteable<T>().In(id).ExecuteCommandHasChangeAsync();
        }

        public virtual async Task<TDto> GetAsync(TPrimaryKeyType id)
        {
            var entity = await _db.Queryable<T>().Where(x => x.Id.Equals(id)).SingleAsync();
            if (entity == null)
                return null;
            else
                return entity.SimpleMapTo<TDto>();
        }

        public abstract Task<PageReturnDto<TDto>> GetPageListAsync(PageReqDto pageReqDto);

        protected async Task<PageReturnDto<TDto>> PageAsync(int pageIndex, int pageSize,
            Expressionable<T> condition, IDictionary<string, string> orderDic)
        {
            if (pageSize <= 0 || pageIndex <= 0)
            {
                return new PageReturnDto<TDto>()
                {
                    PageIndex = pageIndex,
                    PageSize = pageSize,
                    PageCount = 0,
                    TotalCount = 0,
                    Data = null
                };
            }
            // 添加条件
            var queryable = _db.Queryable<T>().WhereNotDelete(condition.ToExpression());
            // 排序
            var tProperties = typeof(T).GetProperties();
            foreach (var item in orderDic.Keys)
            {
                if (!orderDic[item].Equals("asc", StringComparison.OrdinalIgnoreCase)
                    && !orderDic[item].Equals("desc", StringComparison.OrdinalIgnoreCase))
                    continue;
                var orderByType = orderDic[item].Equals("asc", StringComparison.OrdinalIgnoreCase) ? "asc" : "desc";
                var orderByFieldName = _db.EntityMaintenance.GetDbColumnName<T>(item);
                queryable = queryable.OrderBy($"{orderByFieldName} {orderByType} ");
            }
            // 分页查询
            RefAsync<int> total = 0;
            var pageList = await queryable.ToPageListAsync(pageIndex, pageSize, total);

            var result = new PageReturnDto<TDto>()
            {
                PageIndex = pageIndex,
                PageSize = pageSize,
                PageCount = total / pageSize,
                TotalCount = total,
                Data = pageList.Select(x => x.SimpleMapTo<TDto>()).ToList()
            };
            return result;
        }

    }
}
